#pragma warning(disable: 4005)

#include "Win32Platform.h"
#include "Win32Timer.h"
#include "Win32FileSystem.h"
#include "Win32Exception.h"
#include "Win32ViewPort.h"
//Core
#include "NeroCore\NMemoryManager.h"
//Engine
#include "NeroEngine\NEntity.h"
#include "NeroEngine\NInput.h"
//Game
#include "NeroGame\NGame.h"
#include "NeroGame\NDirector.h"
#include "NeroEngine\NGraphics.h"
//Graphics
#include "DirectX\Device.h"

#include "Win32DebugDisplay.h"
#include "Win32Input.h"
#include "Win32Graphics.h"

using namespace Game;
using namespace System;

RTTI_DEFINITIONS(Win32Platform)

extern Game::NGame*			GGame;
extern Engine::NInput*		GInput;
extern bool					GIsRendering;

Win32Platform::Win32Platform(HINSTANCE instance, HINSTANCE, LPSTR, int showCommand)
	:mTimer(NULL),
	 mCamera(NULL),
	 mInstance(instance),
	 mShowCommand(showCommand),
	 mIsInitialized(false)
{
}

Win32Platform::~Win32Platform(void)
{
	Deinitialize();
}

void Win32Platform::Initialize()
{
	if(!mIsInitialized)
	{
		LOGD("Windows Platform Initializing");
		mFileSystem = MY_NEW(Memory::HID_Engine, "Win32FileSystem") Win32FileSystem();
		mFileSystem->Initialize();

		mGraphics = MY_NEW(Memory::HID_Rendering, "Graphics") Win32Graphics();
		Win32Graphics* graphics = (Win32Graphics*)mGraphics;
		if(graphics)
		{
			graphics->Initialize(this, mInstance, mShowCommand);
		}

		mTimer = MY_NEW(Memory::HID_Rendering, "Win32Timer") Win32Timer();
		mTimer->Initialize();

		GInput = MY_NEW(Memory::HID_Engine, "Input") Win32Input();
		GInput->Initialize();

		mViewPort = MY_NEW(Memory::HID_Rendering, "ViewPort") Win32ViewPort();
		mViewPort->Initialize();

		mIsInitialized = true;
	}
}

void Win32Platform::Deinitialize()
{
	if(mViewPort)
	{
		MY_DELETE(mViewPort);
		mViewPort = NULL;
	}

	if(GInput)
	{
		MY_DELETE(GInput);
		GInput = NULL;
	}

	if(mTimer)
	{
		MY_DELETE(mTimer);
		mTimer = NULL;
	}
	
	if(mFileSystem)
	{
		MY_DELETE(mFileSystem);
		mFileSystem = NULL;
	}

	if(mGraphics)
	{
		MY_DELETE(mGraphics);
		mGraphics = NULL;
	}
	mIsInitialized = false;
}

void Win32Platform::Render()
{
	if(!GGame->IsClosing())
	{
		if(mIsInitialized && mGraphics)
		{
			mGraphics->Render();
		}
	}
}

void Win32Platform::Update()
{
	MSG messege;
	if(PeekMessage(&messege, NULL, 0, 0, PM_REMOVE))	// Check to see if any messages are waiting in the queue
	{
		TranslateMessage(&messege);						// Translate the message
		DispatchMessage(&messege);						//dispatch it to WindowProc()
	}

	//Get delta time
	float gameTime = 0;
	if(mTimer)
	{
		Win32Graphics* graphics = (Win32Graphics*)(mGraphics);
		gameTime = mTimer->GetElapsedTime();
		graphics->GetDebugDisplay()->SetDebugText(FPS_ELEMENT, 10, 30, "FPS %i", mTimer->GetFPS());
		graphics->GetDebugDisplay()->SetDebugText(CPU_ELEMENT, 10, 50, "CPU: %i", mTimer->GetCpuPercentage());
		graphics->GetDebugDisplay()->SetDebugText(MEMORY_ELEMENT, 10, 70, "MEMEORY: %i KB", Memory::MemoryManager::GetInstance()->GetUsedMemory() / 1000);
		graphics->GetDebugDisplay()->SetDebugText(TIME_ELEMENT, 10, 90, "TIME : %.2f seconds", mTimer->GetTime());	
	}

	ProcessInput();

	//Update
	if(GInput)
	{
		GInput->Update(gameTime);
	}
	if(mGraphics)
	{
		mGraphics->Update(gameTime);
	}
	if(mCamera)
	{
		mCamera->Update(gameTime);
	}
}

float Win32Platform::GetDeltaTime()
{
	if(mTimer)
	{
		return mTimer->GetElapsedTime();
	}
	return 0.0f;
}

float Win32Platform::GetGameTime()
{
	if(mTimer)
	{
		return mTimer->GetTime();
	}
	return 0.0f;
}

int Win32Platform::GetFPS()
{
	if(mTimer)
	{
		return mTimer->GetFPS();
	}
	return 0;
}

void Win32Platform::SetCamera(Engine::NCamera* cam)
{
	mCamera = cam->As<Graphics::Camera>();
}

Engine::NCamera* Win32Platform::GetCamera()
{
	if(!mCamera)
	{
		throw Win32Exception("Win32Platform::GetCamera - Currect Camera was not set");
	}
	return mCamera;
}

Engine::NDevice* Win32Platform::GetDevice()
{
	if(!mGraphics)
	{
		return NULL;
	}
	return mGraphics->GetDevice();
}

void Win32Platform::ProcessInput()
{
	if(GInput)
	{
		if(GInput->IsKeyDown(VK_ESCAPE))
		{
			GetGame()->EndGame();
		}
	}
}

void Win32Platform::CheckResult(HRESULT result)
{
#if _DEBUG
	switch (result)
	{
	case E_ACCESSDENIED:
		 //MessageBox(NULL, "Access Denied", "Error", MB_OK);  
		break;
	case S_OK:
		break;
	}
#endif
}